home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
081-090
/
amok87
/
hanoi
/
hanoi.mod
< prev
next >
Wrap
Text File
|
1993-11-04
|
8KB
|
184 lines
MODULE Hanoi;
(* ------------------------ *)
(* (c) by Roger Meyer, 1992 *)
(* ------------------------ *)
IMPORT
G : DHanoi, (* Displayroutinen *)
S : Stacks, (* Stack-Verwaltung *)
E : Exec, (* OS: Task/Mem-Manager *)
D : Dos, (* OS: Dos *)
NoGuruRq; (* Oberon: verhindert *)
(* Systemabstuerze *)
CONST
Depth = 9; (* Anzahl Scheiben *)
TYPE
DiskPtr = POINTER TO Disk; (* Pointertyp *)
Disk = RECORD(S.Node); (* Disk: vererbt Eigenschaften von *)
Number : INTEGER; (* Stacks.Node. *)
END; (* Number: Breite der Scheibe *)
VAR
Tower : ARRAY 3 OF S.StackPtr; (* Drei Tuerme *)
DS : INTEGER; (* Dummy INTEGER *)
CONST
Height = 1; (* Hoehe der Scheiben = Height+1 Pkte *)
HStep = Height+2; (* Zwischenraum = 1 Pkt *)
Step = Height*2+2; (* Breitenzuwachs pro Scheibe *)
VStep = 2*(Depth+2)*Step; (* Zwischenraum Stick-Stick *)
Base = Depth*HStep+10; (* Basislinie *)
WinWidth = VStep*3+4*Step; (* Breite der Ausgabe *)
WinHeight = Base+20; (* Hoehe der Ausgabe *)
StOne = VStep DIV 2; (* Standort erster Stick *)
StTwo = StOne+VStep; (* " zweiter " *)
StThree = StOne+VStep*2; (* " dritter " *)
PROCEDURE Display; (* Ausgabe der aktuellen Situation *)
PROCEDURE DisplayStick(Stick : INTEGER); (* Ausgabe eines Sticks *)
VAR
N : S.NodePtr; (* N: Zwischenspeicher *)
Z,C : INTEGER; (* Z: Anz Scheiben auf einem Stick *)
(* C: Counter *)
x,y,h : INTEGER; (* x: X-Pos des Scheibenlochs *)
(* y: Y-Pos des Scheibenlochs *)
(* h: Radius der Scheibe *)
Centre : INTEGER; (* Centre: Mitte des Sticks *)
BEGIN
CASE Stick OF (* Standort des Sticks ermitteln *)
0 : Centre := StOne; (* | *)
| 1 : Centre := StTwo; (* | *)
| 2 : Centre := StThree; (* | *)
END; (* | *)
Z := S.NumberOfNodes(Tower[Stick]); (* Anzahl der Scheiben auf dem Stick *)
C := 0; (* Zaehler initialisieren *)
WHILE C<Z DO (** Schleife 1 **)
N := S.GetNodeNum(Tower[Stick],Z-(C+1)); (* Node Nummer Z-(C+1) merken *)
h := N^(Disk).Number*Step; (* Lok. Type Guard: Groesse des Stick *)
(* auslesen und Breite berechnen *)
y := Base-C*HStep; (* Hoehe ueber der Basis berechnen *)
G.FillRectangle(Centre-h,y-Height,Centre+h,y); (* Scheibe zeichnen *)
INC(C); (* Zaehler erhoehen *)
END; (** Ende Schleife 1, wenn letzte **)
(** Scheibe dargestellt **)
END DisplayStick;
BEGIN
G.ClearScreen(); (* Bild loeschen *)
DisplayStick(0); (* Sticks darstellen *)
DisplayStick(1); (* | *)
DisplayStick(2); (* | *)
D.Delay(5); (* 5/50 sec warten *)
END Display;
PROCEDURE InitTower; (* Programm Initialisieren *)
VAR
Count : INTEGER; (* Zaehler *)
TheDisk : DiskPtr; (* Temporaere Scheibe *)
BEGIN
Tower[0] := S.NewStack(); (* Stacks neu anlegen *)
Tower[1] := S.NewStack(); (* | *)
Tower[2] := S.NewStack(); (* | *)
Count := 0; (* Counter initialisieren *)
WHILE Count<Depth DO (** Schleife 1 **)
NEW(TheDisk); (* Neue Scheibe *)
TheDisk.Number := Depth-Count; (* Groesse setzen *)
S.Put(Tower[0],TheDisk); (* Auf den Stack legen *)
INC(Count); (* Counter erhoehen *)
END; (** Ende Schleife 1, wenn letzte **)
(** Scheibe initialisiert **)
G.SetGraphMode(WinWidth,WinHeight); (* Ausgabe initialisieren *)
END InitTower;
PROCEDURE CleanUp; (* Aufraeumen *)
BEGIN
S.DisposeStack(Tower[0]); (* Stacks loeschen *)
S.DisposeStack(Tower[1]); (* | *)
S.DisposeStack(Tower[2]); (* GarbageCollector fuer die Scheiben *)
G.EndGraphMode; (* Graphik abschalten *)
END CleanUp;
PROCEDURE WhichStack(from,to : INTEGER):INTEGER; (* Stack ermitteln *)
VAR
S : SET;
BEGIN
S := -{from,to}; (* Umkehrmenge von {from,to} *)
IF 0 IN S THEN RETURN 0 END; (* Uebrig bleibt der Stack fuer die *)
IF 1 IN S THEN RETURN 1 END; (* die Verschiebung *)
IF 2 IN S THEN RETURN 2 END; (* | *)
END WhichStack;
PROCEDURE Move(from,to,anz : INTEGER); (* Scheiben von from nach to *)
(* verschieben *)
VAR
TheStack : INTEGER; (* Nummer des Zwischen-Stacks *)
BEGIN
CASE anz OF (* Wenn ... *)
0 : RETURN; (* ... anz=0 => mache nichts *)
(* (Wir sind am Boden) *)
| 1 : S.Put(Tower[to],S.Get(Tower[from]));
(* ... anz=1 => Scheibe verschieben *)
Display; (* und Situation ausgeben *)
ELSE
TheStack := WhichStack(from,to); (* ... sonst => Ermittle 'freier' *)
(* Stack *)
Move(from,TheStack,anz-1); (* Verschiebe alle ausser den *)
(* letzten auf den ZwSpeicher *)
Move(from,to,1); (* Groesste Scheibe verschieben *)
Move(TheStack,to,anz-1); (* ZwSpeicher auf das Ziel *)
END;
END Move;
BEGIN
InitTower; (* 'Towers' initialisieren *)
DS := E.SetTaskPri(E.FindTask(NIL),-5);
(* OS: TaskPrioritaet erniedrigeren *)
Move(0,2,Depth); (* Versch. alle Scheiben von 0 => 2 *)
CLOSE (* Der folgende Code wird unter *)
(* allen Umstaenden ausgefuehrt *)
CleanUp; (* Spielzeug wieder einpacken *)
END Hanoi.